# api/deps.py
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from jose import jwt, JWTError
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select

from db.session import get_db
from extension.ext_redis import get_redis
from models.user import User
from core.config import settings
from redis.asyncio import Redis
from sqlalchemy.orm import selectinload

from services.account_service import AccountService

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/login")


async def get_current_user(
        token: str = Depends(oauth2_scheme),
        db: AsyncSession = Depends(get_db),
        redis: Redis = Depends(get_redis)
):
    try:
        payload = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
        user_id: str = payload.get("sub")
        if user_id is None:
            # raise HTTPException(status_code=401, detail="Invalid token")
            return None
        data = await redis.get(AccountService.get_access_key(token, user_id))
        if not data:
            # raise HTTPException(status_code=401, detail="Invalid token")
            return None
    except JWTError:
        # raise HTTPException(status_code=401, detail="Invalid token")
        return None

    result = await db.execute(select(User).options(selectinload(User.role)).where(User.id == int(user_id)))
    user = result.scalar_one_or_none()
    # if not user:
    #     raise HTTPException(status_code=401, detail="User not found")
    role = user.role
    return user


def require_role(role_name: str):
    async def role_checker(user: User = Depends(get_current_user)):
        if not user or not user.role or user.role.name != role_name:
            raise HTTPException(status_code=403, detail="Permission denied")
        return user

    return role_checker
